#include "zbj_utils.h"
#include <stdlib.h>

int report_msg(int retcode, const char * msg)
{
    printf(msg);
    return retcode;
}

int report_msg_with_newline(int retcode, const char * msg)
{
    printf(msg);
    printf("\n");
    return retcode;
}

int init_charbuf(CharBuf* cb, int len, int delta)
{
    cb->buf = malloc(len);
    if (cb->buf) {
        cb->len = len;
        cb->delta = delta;
        clear_charbuf(cb);
        return 1;
    }
    else {
        return report_msg(0, "Not enough memory in inti_charbuf.\n");
    }
}

int isempty_charbuf(CharBuf* cb)
{
    return !(cb->cursor);
}

int pre_append_to_charbuf(CharBuf* cb, int size)
{
    int empty_space = cb->len-cb->cursor;
    if ( empty_space <= size) {
        int need_extra = size - empty_space;
        int times = need_extra / cb->delta + 1;
        int new_len = cb->len + times * cb->delta;
        char* p = realloc(cb->buf, new_len);
        if (p) {
            cb->buf = p;
            cb->len = new_len;
            return 1;
        }
        else {
            return report_msg(0, "Not enough memory in pre_append_to_charbuf.\n");
        }
    }
    else {
        return 1;
    }
}

int append_substr_to_charbuf(CharBuf* cb, const char* src, int start, int end)
{
    if (pre_append_to_charbuf(cb, end-start)) {
        memcpy(cb->buf + cb->cursor, src+start, end-start);
        cb->cursor += end-start;
        nullterminate_charbuf(cb);
        return 1;
    }
    else {
        return 0;
    }
}

int append_str_to_charbuf(CharBuf* cb, const char* src)
{
    return append_substr_to_charbuf(cb, src, 0, strlen(src));
}

int copy_substr_to_charbuf(CharBuf* cb, const char* str, int start, int end)
{
    clear_charbuf(cb);
    return append_substr_to_charbuf(cb, str, start, end);
}

void clear_charbuf(CharBuf* cb)
{
    cb->cursor = 0;
    nullterminate_charbuf(cb);
}

void nullterminate_charbuf(CharBuf* cb)
{
    cb->buf[cb->cursor] = 0;
}

void free_charbuf(CharBuf* cb)
{
    free(cb->buf);
    cb->cursor=0;
    cb->len=0;
    cb->buf=0;
}

void init_fileContents(FileContents* fc)
{
    fc->file_size = 0;
    fc->contents = 0;
}

int load_file_to_memory(FILE* file, FileContents * fileContent)
{
    fseek(file, 0L, SEEK_END);
    long file_size    = ftell(file);
    long content_size = file_size + 1;
    char* contents    = (char*)malloc(content_size);
    if (!contents) {
        return report_msg(0, "Not enough memory in load_file_to_memory.\n");
    }
    contents[file_size] = 0;

    fseek(file, 0L, SEEK_SET);
    if (fread(contents, file_size, 1, file) != 1) {
        return report_msg(0, "Read file content failed in load_file_to_memory.\n");
    }

    fileContent->file_size = file_size;
    fileContent->contents  = contents;

    return 1;
}

void unload_file_from_memory(FileContents * fileContent)
{
    if (fileContent && fileContent->contents) {
        free(fileContent->contents);
        fileContent->contents = 0;
    }
}

int setup_reg_context(reg_context* context, const char* pattern, int cflags, const char* text, int text_len, int eflags)
{
    int ret;

    context->text=text;
    context->text_end=text+text_len;
    context->last_pos=text;
    context->cflags=cflags;
    context->eflags=eflags;
    context->nmatch=0;
    regex_t* regex = &context->regex;

    ret = regcomp(regex, pattern, cflags);
    if (ret) {
        char ebuf[128];
        regerror(ret, regex, ebuf, sizeof(ebuf));
        fprintf(stderr, "%s: pattern '%s'\n", ebuf, pattern);
        return ret;
    }
    else {
        printf("pattern: %s\n", pattern);
    }

    for (int x=0; x<NMATCH; x++) {
        context->pm[x].rm_so = -1;
        context->pm[x].rm_eo = -1;
    }
    context->pm[NMATCH].rm_so = 0;
    context->pm[NMATCH].rm_eo = 0;

    return 0;
}

int regexec_next(reg_context* context)
{
    int ret;
    const char* new_pos = context->last_pos + context->pm[NMATCH].rm_eo;
    if (new_pos >= context->text_end) {
        return REG_NOMATCH;
    }

    ret = regexec(&context->regex, new_pos, NMATCH, context->pm, context->eflags);
    if (ret == REG_NOMATCH) {
        return ret;
    }
    else if (ret) {
        char ebuf[128];
        regerror(ret, &context->regex, ebuf, sizeof(ebuf));
        fprintf(stderr, "%s: regexec('%s')\n", ebuf, context->text);
        return ret;
    }
    else {
        int x;
        for (x=0; x!=NMATCH && context->pm[x].rm_so != -1; x++) {
        }

        context->nmatch = x;

        context->pm[NMATCH].rm_so=context->pm[0].rm_so;
        context->pm[NMATCH].rm_eo=context->pm[0].rm_eo;

        if (context->pm[NMATCH].rm_so >= context->pm[NMATCH].rm_eo) {
            return REG_NOMATCH;
        }

        context->last_pos = new_pos;

        return 0;
    }
}

void destroy_reg_context(reg_context* context)
{
    regfree(&context->regex);
}

int reg_match_item_length(reg_context* context, int match_index)
{
    return (context->pm[match_index].rm_eo - context->pm[match_index].rm_so);
}

